/*
 * Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.cloudphoneime;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.inputmethodservice.InputMethodService;
import android.view.KeyEvent;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;

public class CaeImeService extends InputMethodService {
    private static final String TAG = "CloudPhoneIme";
    private CaeImeServer mImeServer;
    private CaeImeRequest mImeRequest;

    public CaeImeService() {
        mImeRequest = null;
        mImeServer = CaeImeServer.defaultImeServer();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mImeServer.setRequestListener(new NewRequestListener());
        mImeServer.start();
        CaeImeLog.i(TAG, "Ime service on create.");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mImeServer.stop();
        if (mImeRequest != null) {
            mImeRequest.stopProcess();
            mImeRequest = null;
        }
        CaeImeLog.i(TAG, "Ime service on destroy.");
    }

    @Override
    public void showWindow(boolean showInput) {
        super.showWindow(showInput);
        if (mImeRequest != null) {
            String text = getCurrentText();
            CaeImeProtocol.IMEShowKeyBoardPkt showKeyBoardPkt;
            if (text == null) {
                showKeyBoardPkt = new CaeImeProtocol.IMEShowKeyBoardPkt(null);
            } else {
                showKeyBoardPkt = new CaeImeProtocol.IMEShowKeyBoardPkt(text.getBytes());
            }
            byte[] data = showKeyBoardPkt.get();
            int res = mImeRequest.send(data);
            if (res < 0) {
                CaeImeLog.e(TAG, "Send show keyboard msg failed.");
                return;
            }
            String clipContent = getClipBoardContent();
            if (clipContent == null || clipContent.length() == 0) {
                return;
            }
            CaeImeProtocol.IMEClipBoardContentPkt clipBoardContentPkt = new CaeImeProtocol.IMEClipBoardContentPkt(clipContent);
            byte[] clipBoardPkt = clipBoardContentPkt.get();
            if (clipBoardPkt == null) {
                return;
            }
            mImeRequest.send(clipBoardPkt);
        }
    }

    @Override
    public void hideWindow() {
        super.hideWindow();
        if (mImeRequest != null) {
            CaeImeProtocol.IMEHideKeyBoardPkt hideKeyBoardPkt = new CaeImeProtocol.IMEHideKeyBoardPkt();
            byte[] data = hideKeyBoardPkt.get();
            mImeRequest.send(data);
        }
    }

    private String getCurrentText() {
        InputConnection ic = getCurrentInputConnection();
        if (ic == null) {
            return null;
        }
        ExtractedText extractedText = ic.getExtractedText(new ExtractedTextRequest(), 0);
        if (extractedText == null) {
            return null;
        }
        CharSequence curPos = extractedText.text;
        if (curPos == null) {
            return null;
        }
        CharSequence beforePos = ic.getTextBeforeCursor(curPos.length(), 0);
        CharSequence afterPos = ic.getTextAfterCursor(curPos.length(), 0);
        return beforePos.toString() + afterPos.toString();
    }

    private String getClipBoardContent() {
        Context context = this.getApplicationContext();
        ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        if (cm == null) {
            return null;
        }
        ClipData data = cm.getPrimaryClip();
        if (data == null) {
            return null;
        }
        ClipData.Item item = data.getItemAt(0);
        if (item == null) {
            return null;
        }
        return item.getText().toString();
    }

    class NewRequestListener implements CaeImeRequestListener {
        @Override
        public void onNewRequest(CaeImeRequest caeImeRequest) {
            if (mImeRequest != null) {
                mImeRequest.stopProcess();
                mImeRequest = null;
            }
            mImeRequest = caeImeRequest;
            mImeRequest.setTextChangeListener(new TextChangeListener());
            mImeRequest.startProcess();
        }
    }

    class TextChangeListener implements CaeImeEditChangeListener {

        @Override
        public void onRecvText(byte[] data) {
            String text = new String(data);
            commitText(text);
        }

        @Override
        public void onRecvKeyEvent(int keycode) {
            InputConnection ic = getCurrentInputConnection();
            ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keycode));
        }

        private void commitText(String text) {
            InputConnection ic = getCurrentInputConnection();
            if (ic == null) {
                return;
            }
            ExtractedText extractedText = ic.getExtractedText(new ExtractedTextRequest(), 0);
            if (extractedText == null) {
                return;
            }
            CharSequence curPos = extractedText.text;
            CharSequence beforePos = ic.getTextBeforeCursor(curPos.length(), 0);
            CharSequence afterPos = ic.getTextAfterCursor(curPos.length(), 0);
            String currentText = beforePos.toString() + afterPos.toString();
            if (currentText != null && currentText.equals(text)) {
                return;
            }
            ic.deleteSurroundingText(beforePos.length(), afterPos.length());
            ic.commitText(text, 1);
        }
    }
}